home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************************
- *
- * ScrollDialog.c- A useful library for implementing scrollable text boxes in
- * a dialog. Can be used for elaborate about boxes, etc.
- *
- * ©1993 by Graham Cox. All Rights Reserved.
- *
- * 20/3/93 Modified to allow edit operations if required.
- * 10/2/94 Routines added to support SimpleHelp library
- * 10/2/94 Dependency on xAlert library removed
- * 13/7/94 Converted to Universal Headers and compiled for PowerPC
- *
- ***************************************************************************************/
-
- /*
-
- Basic operation. This library requires that you set up a dialog box in a certain way in
- order to use it properly. For versatility, both a high level and a low level interface
- is provided, for the purposes for which this code was designed, the high level inter-
- face is generally the most useful.
-
- Putting scrollable styled text into a dialog is a bit of a chore, in that it requires
- three tedious custom procedures- a user item proc to draw it, a filter proc to handle
- the scroll bar properly, and a control action proc to scroll the text. By bundling these
- functions into a high level dialog call, all this is taken care of for you. This library
- can be used with most dialog templates, the only prerequisite is that you create a user
- item to delineate the area to display the text as part of the dialog template. The
- scrollbar is created for you at run time, and is positioned on the right of the useritem.
-
- The high level call requires an ID for the template, the item number of the useritem
- to use for the text, and the item number of a TEXT resource. The dialog is set up and
- displayed, then handled. For this call, a hit in any enabled item will close the dialog
- and return, so in this respect it acts like a special alert box. For more control, you
- will need to handle hits yourself. The only restriction in this case is that you don't
- require a custom filter yourself- as one is already in use, you will need to do every-
- thing yourself if you need very complex dialog handling. In this case I would suggest
- you use a window anyway.
-
- */
-
- #include "ScrollDialog.h"
- #include "ColourPopUp.h"
-
- /****************************************************************************************
-
- INTERNAL FUNCTIONS
- */
-
-
-
- pascal void TDUserItem(DialogPtr theDialog,short theItem)
- {
- /* draws text in user item using textedit. Dialog's RefCon is handle to text rec */
-
- short itemType;
- Handle itemHand;
- Rect itemBox;
- TDRecHdl temp;
-
- if (theDialog != NIL)
- {
- GetDItem(theDialog,theItem,&itemType,&itemHand,&itemBox);
- temp = (TDRecHdl) GetWRefCon(theDialog);
- if (temp != NIL)
- {
- //EraseRect(&itemBox);
- TEUpdate(&itemBox,(*temp)->TDText);
- }
- Frame3DRect(&itemBox,FALSE);
- FrameRect(&itemBox);
- }
- }
-
-
- pascal void TDScrollProc(ControlHandle theControl,short partCode)
- {
- /* scrolls text when scroll bar is tracked */
-
- short oldValue,newValue;
- TDRecHdl temp;
- TEHandle theText;
-
- if (theControl != NIL)
- {
- temp = (TDRecHdl) GetCRefCon(theControl);
- oldValue = newValue = GetCtlValue(theControl);
- switch (partCode)
- {
- case inUpButton:
- newValue -= (*temp)->lineHeight;
- break;
- case inDownButton:
- newValue += (*temp)->lineHeight;
- break;
- case inPageUp:
- newValue -= (*temp)->pageHeight;
- break;
- case inPageDown:
- newValue += (*temp)->pageHeight;
- break;
- default:
- break;
- }
- SetCtlValue(theControl,newValue);
- newValue = GetCtlValue(theControl);
- theText = (*temp)->TDText;
- if (theText != NIL)
- TEScroll(0,oldValue - newValue,theText);
- }
- }
-
-
- pascal Boolean TDFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
- {
- /* this is the filter proc to implement auto scrolling and everything else */
-
- Point mClick;
- ControlHandle theControl = NIL;
- short partCode,itemType,ctlShift;
- char theKey;
- Handle itemHand;
- Rect itemBox;
- long dTime;
- TEHandle theText;
- TDRecHdl temp;
- GrafPtr savePort;
- Boolean canWrite;
- CursHandle theCursor;
- ControlActionUPP gVActionUPP;
-
- if (theDialog != NIL)
- {
- GetPort(&savePort);
- SetPort(theDialog);
-
- temp = (TDRecHdl) GetWRefCon(theDialog);
- if (temp != NIL)
- {
- theText = (*temp)->TDText;
-
- canWrite = (*temp)->editable;
- if (canWrite)
- {
- TEIdle(theText);
- GetMouse(&mClick);
- if (PtInRect(mClick,&(*theText)->viewRect))
- {
- theCursor = GetCursor(iBeamCursor);
- SetCursor (*theCursor);
- }
- else
- InitCursor();
- }
- switch (theEvent->what)
- {
- case mouseDown:
- mClick = theEvent->where;
- GlobalToLocal(&mClick);
-
- partCode = FindControl(mClick,theDialog,&theControl);
- if ((theControl != NIL) && (theControl == (*temp)->TDControl))
- {
- if (partCode == inThumb)
- {
- *itemHit = 0;
- ctlShift = GetCtlValue(theControl);
- partCode = TrackControl(theControl,mClick,NIL);
- if (partCode == inThumb) {
- ctlShift -= GetCtlValue(theControl);
- TEScroll(0,ctlShift,theText);
- }
- }
- else
- {
- gVActionUPP = NewControlActionProc((ProcPtr) TDScrollProc);
- partCode = TrackControl(theControl,mClick,gVActionUPP);
- DisposeRoutineDescriptor(gVActionUPP);
- *itemHit = 0;
- }
- SetPort(savePort);
- return(TRUE);
- }
- else
- {
- /* not our special scrollbar, so just return FALSE, let it be handled
- by the dialog manager- it doesn't do a lot for its living */
-
- if (canWrite)
- {
- if (PtInRect(mClick,&(*theText)->viewRect))
- {
- TEClick(mClick,(theEvent->modifiers & shiftKey) == shiftKey,theText);
- UpdateTDBar(theText,(*temp)->TDControl);
- }
- }
- SetPort(savePort);
- return(FALSE);
- }
- break;
- case keyDown:
- case autoKey:
- theKey = theEvent->message & charCodeMask;
- if (canWrite)
- {
- /* edit flag TRUE, so pass key presses to text */
- TEKey(theKey,theText);
- UpdateTDBar(theText,(*temp)->TDControl);
- }
- else
- {
- if (theKey == 0x0D || theKey == 0x03)
- {
- GetDItem(theDialog,1,&itemType,&itemHand,&itemBox);
- HiliteControl((ControlHandle)itemHand,1);
- Delay(8,&dTime);
- HiliteControl((ControlHandle)itemHand,0);
- *itemHit = 1;
- SetPort(savePort);
- return(TRUE);
- }
- }
- break;
- default:
- break;
- }
- }
- SetPort(savePort);
- }
- return(FALSE);
- }
-
-
- pascal DialogPtr GetTextDialog(short dialogID,short textUserItem,short textResourceID,Boolean canWrite)
- {
- /* gets a dialog of the required ID, then sets up the given user item as a scrollable
- text item using the text resource passed. If the text resource doesn't exist,
- then you'll need to install the text yourself */
-
- DialogPtr theDialog = NIL;
- TDRecHdl temp;
- TEHandle theText;
- ControlHandle tdBar;
- short itemType,tHeight;
- Handle itemHand,textRes;
- Rect itemBox,tdBarRect;
- GrafPtr savePort;
- StScrpHandle stRec = NIL;
- FontInfo fInfo;
- short saveFont,saveSize,saveFace;
- static UserItemUPP gMyUserItemUPP;
-
- theDialog = GetNewDialog(dialogID,NIL,(WindowPtr) -1L);
- if (theDialog != NIL)
- {
- GetDItem(theDialog,textUserItem,&itemType,&itemHand,&itemBox);
- GetPort(&savePort);
- SetPort(theDialog);
-
- if ((itemType & 0x007F) == userItem)
- {
- /* it really is a user item so set its procedure up */
- temp = (TDRecHdl) NewHandle(sizeof(TDRecord));
- SetWRefCon(theDialog,(long) temp);
- if (temp != NIL)
- {
- saveFont = theDialog->txFont;
- saveSize = theDialog->txSize;
- saveFace = theDialog->txFace;
-
- gMyUserItemUPP = NewUserItemProc((ProcPtr) TDUserItem);
- itemHand = (Handle) gMyUserItemUPP;
- SetDItem(theDialog,textUserItem,itemType,itemHand,&itemBox);
-
- TextFont(geneva);
- TextSize(9);
-
- GetFontInfo(&fInfo);
- SetRect(&tdBarRect,0,0,16,itemBox.bottom - itemBox.top);
- itemBox.right -= 16;
- OffsetRect(&tdBarRect,itemBox.right,itemBox.top);
- InsetRect(&itemBox,3,3);
- (*temp)->lineHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
- (*temp)->pageHeight = (itemBox.bottom - itemBox.top) -
- (*temp)->lineHeight;
- (*temp)->editable = canWrite;
-
- theText = TEStylNew(&itemBox,&itemBox);
- tdBar = NewControl(theDialog,&tdBarRect,"\p",TRUE,0,0,100,16,0);
-
- (*temp)->TDText = theText;
- (*temp)->TDControl = tdBar;
- (*temp)->reserved = 0;
-
- /* ready to go- try loading the text */
-
- if (theText != NIL)
- {
- textRes = GetResource('TEXT',textResourceID);
- if (textRes != NIL)
- {
- stRec = (StScrpHandle) GetResource('styl',textResourceID);
-
- HLock(textRes);
- TEStylInsert(*textRes,GetHandleSize(textRes),stRec,theText);
- HUnlock(textRes);
-
- ReleaseResource(textRes);
- if (stRec != NIL)
- ReleaseResource((Handle) stRec);
- }
- tHeight = TEGetHeight(0,32767,theText) -
- (itemBox.bottom - itemBox.top);
- if (tHeight < 0)
- tHeight = 0;
- if (tdBar != NIL)
- {
- SetCtlMax(tdBar,tHeight);
- SetCRefCon(tdBar,(long) temp);
- }
-
- if (canWrite)
- {
- TEAutoView(TRUE,theText);
- TEActivate(theText);
- }
- }
-
- TextFont(saveFont);
- TextSize(saveSize);
- TextFace(saveFace);
- }
- SetPort(savePort);
- }
- }
- return(theDialog);
- }
-
-
- pascal void DisposeTDDialog(DialogPtr theDialog)
- {
- /* disposes of dialog and all internal structures created */
-
- TDRecHdl temp;
- TEHandle theText;
- ControlHandle tdBar;
-
- if (theDialog != NIL)
- {
- temp = (TDRecHdl) GetWRefCon(theDialog);
- if (temp != NIL)
- {
- theText = (*temp)->TDText;
- tdBar = (*temp)->TDControl;
-
- if (theText != NIL)
- TEDispose(theText);
-
- if (tdBar != NIL)
- DisposeControl(tdBar);
-
- DisposHandle((Handle)temp);
- }
- DisposDialog(theDialog);
- }
- }
-
-
- pascal void ModalTDDialog(short *theItem)
- {
- ModalFilterUPP gTDFilterUPP;
-
- gTDFilterUPP = NewModalFilterProc((ProcPtr) TDFilter);
- ModalDialog(gTDFilterUPP,theItem);
- DisposeRoutineDescriptor(gTDFilterUPP);
- }
-
-
- pascal short ScrollTextDialog(short dialogID,short textUserItem,short textResourceID)
- {
- /* high level alert-like call to display scrolly text dialog box */
-
- DialogPtr theDialog;
- Handle itemHand;
- Rect itemBox;
- short theItem = 0,itemType;
- GrafPtr savePort;
-
- theDialog = GetTextDialog(dialogID,textUserItem,textResourceID,FALSE);
- if (theDialog != NIL)
- {
- ShowWindow(theDialog);
- SelectWindow(theDialog);
-
- GetDItem(theDialog,ok,&itemType,&itemHand,&itemBox);
- InsetRect(&itemBox,-4,-4);
- GetPort(&savePort);
- SetPort(theDialog);
- PenSize(3,3);
- FrameRoundRect(&itemBox,16,16);
- PenNormal();
- SetPort(savePort);
-
- while (theItem == 0)
- ModalTDDialog(&theItem);
-
- DisposeTDDialog(theDialog);
- }
- return(theItem);
- }
-
-
- pascal void TDSetText(DialogPtr theDialog,Ptr text,long tLength,StScrpHandle stInfo)
- {
- /* sets the text in the TD dialog to be the given text. If you pass a style record
- the text will be styled using that record. The scrollbar etc is recalculated
- for the amount of text, and reset to the first line. Using this, multi-page
- scrollable text can be implemented */
-
- TDRecHdl temp;
- TEHandle theText;
- ControlHandle tdBar;
- short tHeight;
- Rect tdBarRect;
- GrafPtr savePort;
-
- if (theDialog != NIL)
- {
- temp = (TDRecHdl) GetWRefCon(theDialog);
-
- if (temp != NIL)
- {
- theText = (*temp)->TDText;
-
- if (theText != NIL)
- {
- if ((*temp)->editable)
- TEDeactivate(theText);
-
- (*theText)->destRect = (*theText)->viewRect;
- TESetSelect(0,32767,theText);
- TEDelete(theText);
- GetPort(&savePort);
- SetPort(theDialog);
-
- if (stInfo == NIL)
- {
- TESetText(text,tLength,theText);
- InvalRect(&(*theText)->viewRect);
- }
- else
- TEStylInsert(text,tLength,stInfo,theText);
-
- TECalText(theText);
- tdBar = (*temp)->TDControl;
- SetPort(savePort);
-
- if (tdBar != NIL)
- {
- tdBarRect = (*tdBar)->contrlRect;
- InsetRect(&tdBarRect,0,3);
- tHeight = TEGetHeight(0,32767,theText) -
- (tdBarRect.bottom - tdBarRect.top);
- if (tHeight < 0)
- tHeight = 0;
- SetCtlMax(tdBar,tHeight);
- SetCtlValue(tdBar,0);
- }
- if ((*temp)->editable)
- TEActivate(theText);
-
- }
- }
- }
- }
-
-
- pascal void TDSetResourceText(DialogPtr theDialog,short textResID)
- {
- /* gets a 'TEXT' resource (& 'styl' if available) and calls TDSetText with it */
-
- Handle text,style;
-
- text = GetResource('TEXT',textResID);
- if (text != NIL)
- {
- style = GetResource('styl',textResID);
-
- HLock(text);
- TDSetText(theDialog,*text,GetHandleSize(text),(StScrpHandle) style);
- HUnlock(text);
-
- ReleaseResource(text);
- if (style != NIL)
- ReleaseResource(style);
- }
- }
-
-
- pascal TEHandle GetTDTextHdl(DialogPtr theDialog)
- {
- /* utility to return text handle for direct manipulation */
-
- TDRecHdl temp;
- TEHandle theText = NIL;
-
- if (theDialog != NIL)
- {
- temp = (TDRecHdl) GetWRefCon(theDialog);
- if (temp != NIL)
- theText = (*temp)->TDText;
- }
- return(theText);
- }
-
-
- pascal void UpdateTDBar(TEHandle theText,ControlHandle theBar)
- {
- /* calculates how much the text record is scrolled and updates the scrollbar. This is
- done after an autoscroll operation */
-
- short pOffset,tHeight;
- Rect tdBarRect;
-
- tdBarRect = (*theBar)->contrlRect;
- InsetRect(&tdBarRect,0,3);
- tHeight = TEGetHeight(0,32767,theText) -
- (tdBarRect.bottom - tdBarRect.top);
- if (tHeight < 0)
- tHeight = 0;
- SetCtlMax(theBar,tHeight);
- pOffset = (*theText)->viewRect.top - (*theText)->destRect.top;
- SetCtlValue(theBar,pOffset);
- }
-
-
- pascal void RecalTDBar(DialogPtr theDialog)
- {
- /* recomputes parameters for the scroll bar. This is necessary if you change anything
- during editing of the text */
-
- TDRecHdl temp;
-
- if (theDialog != NIL)
- {
- temp = (TDRecHdl)GetWRefCon(theDialog);
- if (temp != NIL)
- UpdateTDBar((*temp)->TDText,(*temp)->TDControl);
- }
- }
-
-
- /*----------------------------------------------------------------------------------------
- Support added for modeless dialog 10/2/94
- ----------------------------------------------------------------------------------------*/
-
- pascal Boolean ModelessText(DialogPtr theDialog,short theItem,EventRecord *theEvent)
- {
- /* handles the modeless dialog case. This function should be called when DIALOGSELECT
- returns a value of TRUE, for a dialog containing a text panel. This handles the
- hits in the panel as for the modal case, and editing if that is enabled. If some
- other item in the dialog is hit, then the function returns FALSE and you must then
- handle it yourself. WARNING!!! The dialog passed MUST be a scrolly-text type. It is
- your responsibility to check first.
- */
-
- if (theDialog != NIL)
- {
- return(TDFilter(theDialog,theEvent,&theItem));
- }
- }